package es.mahulo.battleship.service;

import java.util.List;

import org.apache.log4j.Logger;
import org.springframework.stereotype.Service;

import es.mahulo.battleship.api.service.Config;
import es.mahulo.battleship.model.Cell;
import es.mahulo.battleship.model.Game;
import es.mahulo.battleship.model.GameConfig;
import es.mahulo.battleship.model.Player;
import es.mahulo.battleship.model.Ship;
import es.mahulo.battleship.model.ShipConfig;
import es.mahulo.battleship.model.ShipExecption;

@Service
public class ConfigImpl implements Config {

	Logger  logger = Logger.getLogger(ConfigImpl.class.getName());
	
	
	public void isValid (Game game, Player player, Ship ship) throws ShipExecption {
		logger.info("isValid " + game + " " +  player + " " + ship );
		
		
		
		checkCells(ship);
		checkSize(ship);
		checkNumberOfShip (ship, player);

		for ( Cell cell : ship.getCells() ) {
			
			logger.debug("Checking cell " + 
							cell + 
							" between " + 
							game.getGameConfig().getDimensionX() 
							+ " and " 
							+ game.getGameConfig().getDimensionY() );
			
			checkInsideBoard (cell, game.getGameConfig());
			checkNotUsedCell(player.getShips(), cell);
		}
		
	}
	
	private void checkCells (Ship ship) throws ShipExecption {
		logger.info("checkCells " +  ship );
		
		if (ship.getCells() == null || 
				ship.getCells().size() == 0 ) {
			
			logger.error("No cells " + ship );
			
			throw new ShipExecption("No cells " + ship);
		}
		
		logger.info("checkCells ok");
	}
	
	private void checkSize (Ship ship) throws ShipExecption {
		logger.info("checkSize " +  ship );
		
		if (ship.getCells().size() != ship.getShipConfig().getSize()) {
			logger.error("Size of the ship is incorrect " + ship );
			
			throw new ShipExecption("Size of the ship is incorrect " + ship);
		}
		
		logger.info("checkSize ok");
	}
	
	
	private void checkNumberOfShip (Ship ship,Player player) throws ShipExecption {
		logger.info("checkNumberOfShip " +  ship  + " " + player);
		
		Integer numberOfShipThisType = 0;
		List<Ship> ships = player.getShips();
		for (Ship aShip : ships) {
			if (aShip.getShipConfig().getId()==ship.getShipConfig().getId() ) {
				numberOfShipThisType++;
			}
		}
		
		logger.debug("Number of ship of this type " + numberOfShipThisType );
		
		
		if ( ( numberOfShipThisType + 1 ) > ship.getShipConfig().getNumber() )  {
			
			logger.error("Number of ship incorrect " + ship.getShipConfig().getName());
			
			throw new ShipExecption("Number of ship incorrect " + ship.getShipConfig().getName());
		}
		
		logger.info("checkNumberOfShip ok");
			
	}
	
	private void checkInsideBoard (Cell cell, GameConfig gameConfig) throws ShipExecption {
		logger.info("checkInsideBoard " +  cell  + " " + gameConfig);
		
		if ( ( cell.getX() < 1 ) ||
			 ( cell.getX() > gameConfig.getDimensionX() ) ||
			 ( cell.getY() < 1 ) ||
			 ( cell.getY() > gameConfig.getDimensionY() ) ) {
			
			logger.error(" Position of ship incorrect: outside dimensions " + cell);
			
			throw new ShipExecption(" Position of ship incorrect: outside dimensions " + cell);
		}
	
		logger.info("checkInsideBoard ok");
			
	}

	private void checkNotUsedCell(List<Ship> ships, Cell cell) throws ShipExecption {
		logger.info("checkNotUsedCell " +  ships  + " " + cell);
		
		for( Ship aShip : ships) {
			for(Cell aCell: aShip.getCells()) { 
				for (int i=-1;i<2;i++)  {
					for (int j=-1;j<2;j++) { 
						if( ( ( cell.getX() -i )==aCell.getX() ) && 
								( ( cell.getY() -j )==aCell.getY() ) ) {
							
							logger.error(" Position of ship incorrect: not empty " + cell);
							
							throw new ShipExecption(" Position of ship incorrect: not empty " + cell);
						}
					}
				}
			}
		}
		logger.info("checkNotUsedCell ok");
		
	}

	
	//TODO CHECKS THE SHIPS ARE HORIzONTAL OR VERTICAL.
	
	
	public boolean isComplete(GameConfig gameConfig, Player player) {
		logger.info("isComplete " + gameConfig + " " + player);
		
		
		List<ShipConfig> shipConfigs = gameConfig.getShipConfigs();
		
		for (ShipConfig shipConfig : shipConfigs) {
			
			Integer expectedNumber = shipConfig.getNumber();
			
			Integer foundNumber = 0;
			List<Ship> ships = player.getShips();
			for (Ship ship : ships) {
				
				logger.debug(ship.getShipConfig().getId() + " " + shipConfig.getId()+ " " + 
						( ship.getShipConfig().getId().longValue() == shipConfig.getId().longValue() ));
				
				if (ship.getShipConfig().getId().longValue() == shipConfig.getId().longValue()) {
					foundNumber++;
				}
			}
			
			logger.debug("shipConfig found: " +foundNumber + " expected: "  + expectedNumber);
			
			if (foundNumber!=expectedNumber) {
				
				
				
				return false;
			}
		}
		return true;
	}
}
